package com.xxg.renrensearch.dao;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.model.Indexes;
import com.xxg.renrencommon.domain.bean.CarryProductInfo;
import com.xxg.renrencommon.domain.filedenum.productenum.CarryProductStatusEnum;
import com.xxg.renrensearch.domain.result.CarriedSpuResult;
import com.xxg.renrensearch.domain.result.CarryCountResult;
import org.bson.Document;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import static org.springframework.data.mongodb.core.query.Criteria.where;

/**
 * 带货信息dao
 *
 * @author szj
 * @date 2021/11/29
 */
@Repository
public class CarryProductInfoDao {
    private final MongoTemplate mongoTemplate;

    public CarryProductInfoDao(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
        createCollection();
    }

    /**
     * 创建collection
     */
    private void createCollection() {
        String collectionName = "carryProductInfo";
        MongoCollection<Document> collection;
        if (!mongoTemplate.getCollectionNames().contains(collectionName)) {
            collection = mongoTemplate.createCollection(CarryProductInfo.class);
            createIndex(collection);
        }
    }

    /**
     * 创建索引
     *
     * @param collection 数据集
     */
    private void createIndex(MongoCollection<Document> collection) {
        IndexOptions indexOptions = new IndexOptions().unique(true);
        collection.createIndex(Indexes.ascending("userId"));
        collection.createIndex(Indexes.ascending("shopId"));
        collection.createIndex(Indexes.ascending("spuId"));
        collection.createIndex(Indexes.compoundIndex(Indexes.ascending("shopId"), Indexes.ascending("spuId")), indexOptions);
    }

    /**
     * 查询带货的商品数量，并根据原店铺ID分组统计数量
     *
     * @return 成功带货的商品数量
     */
    public List<CarryCountResult> getCountByShopIdGroupByOriShopId() {
        List<AggregationOperation> operations = new ArrayList<>();
        operations.add(match(where("status").in(CarryProductStatusEnum.NORMAL.getValue(),
                CarryProductStatusEnum.VERIFY_PASS.getValue())));
        GroupOperation groupOperation = group("shopId", "originShopId")
                .first("shopId").as("shopId")
                .first("originShopId").as("originShopId")
                .count().as("count");
        operations.add(groupOperation);
        Aggregation agg = newAggregation(operations);
        AggregationResults<CarryCountResult> results = mongoTemplate.aggregate(agg, CarryProductInfo.class,
                CarryCountResult.class);
        return results.getMappedResults();
    }

    /**
     * 根据原店铺ID和查询店铺ID查询已经带货的商品列表
     *
     * @param shopId    查询店铺ID
     * @param oriShopId 原店铺ID
     * @return 结果
     */
    public List<CarryProductInfo> getSpuIdsByShopIdAndOriShopId(Integer shopId, Integer oriShopId) {
        Query query = new Query(where("originShopId").is(oriShopId).and("shopId").is(shopId)
                .and("status").in(CarryProductStatusEnum.NORMAL.getValue(),
                        CarryProductStatusEnum.VERIFY_PASS.getValue()));
        query.fields().include("spuId");
        return mongoTemplate.find(query, CarryProductInfo.class);
    }

    /**
     * 查询店铺已带货的商品数量
     *
     * @param shopId 店铺ID
     * @return 结果
     */
    public int findCarriedCountByShopId(Integer shopId) {
        Query query = new Query(where("shopId").is(shopId).and("status").in(CarryProductStatusEnum.NORMAL.getValue(),
                CarryProductStatusEnum.VERIFY_PASS.getValue()));
        return (int) mongoTemplate.count(query, CarryProductInfo.class);
    }

    /**
     * 查询店铺被带货的商品数量
     *
     * @param shopId 店铺ID
     * @return 结果
     */
    public int findBeCarriedCountByShopId(Integer shopId) {
        Query query = new Query(where("originShopId").is(shopId)
                .and("status").in(CarryProductStatusEnum.NORMAL.getValue(),
                        CarryProductStatusEnum.VERIFY_PASS.getValue()));
        return (int) mongoTemplate.count(query, CarryProductInfo.class);
    }

    /**
     * 查询店铺已带货的信息按照店铺分组
     *
     * @param shopId 店铺ID
     * @param pageNo 页码
     * @return 结果
     */
    public List<CarriedSpuResult> findCarriedSpusGroupByShop(Integer shopId, Integer pageNo) {
        List<AggregationOperation> operations = new ArrayList<>();
        // 查询
        operations.add(match(where("shopId").is(shopId).and("status").in(CarryProductStatusEnum.NORMAL.getValue(),
                CarryProductStatusEnum.VERIFY_PASS.getValue())));
        // 排序
        operations.add(sort(Sort.by(Sort.Order.desc("createTime"))));
        // 分组
        GroupOperation groupOperation = group("originShopId")
                .first("originShopId").as("shopId")
                .push("spuId").as("spuIds")
                .push("createTime").as("createTimes");
        operations.add(groupOperation);
        // 分页
        long pageSize = 10;
        operations.add(skip((pageNo - 1) * pageSize));
        operations.add(limit(pageSize));
        Aggregation agg = newAggregation(operations);
        AggregationResults<CarriedSpuResult> results = mongoTemplate.aggregate(agg, CarryProductInfo.class,
                CarriedSpuResult.class);
        return results.getMappedResults();
    }

    /**
     * 查询店铺被带货的信息按照店铺分组
     *
     * @param shopId 店铺ID
     * @param pageNo 页码
     * @return 结果
     */
    public List<CarriedSpuResult> findBeCarriedSpusGroupByShop(Integer shopId, Integer pageNo) {
        List<AggregationOperation> operations = new ArrayList<>();
        // 查询
        operations.add(match(where("originShopId").is(shopId).and("status").in(CarryProductStatusEnum.NORMAL.getValue(),
                CarryProductStatusEnum.VERIFY_PASS.getValue())));
        // 排序
        operations.add(sort(Sort.by(Sort.Order.desc("createTime"))));
        // 分组
        GroupOperation groupOperation = group("shopId")
                .first("shopId").as("shopId")
                .push("carrySpuId").as("spuIds")
                .push("createTime").as("carriedTimes");
        operations.add(groupOperation);
        // 分页
        long pageSize = 10;
        operations.add(skip((pageNo - 1) * pageSize));
        operations.add(limit(pageSize));
        Aggregation agg = newAggregation(operations);
        AggregationResults<CarriedSpuResult> results = mongoTemplate.aggregate(agg, CarryProductInfo.class,
                CarriedSpuResult.class);
        return results.getMappedResults();
    }

    /**
     * 根据店铺ID查询已带货的商品ID列表
     *
     * @param shopId 店铺ID
     * @param pageNo 页码
     * @return 结果
     */
    public List<CarryProductInfo> findCarriedSpusByShopId(Integer shopId, Integer pageNo) {
        Query query = new Query(where("shopId").is(shopId).and("status").in(CarryProductStatusEnum.NORMAL.getValue(),
                CarryProductStatusEnum.VERIFY_PASS.getValue()));
        query.fields().include("spuId");
        long pageSize = 10;
        query.skip((pageNo - 1) * pageSize).limit((int) pageSize);
        return mongoTemplate.find(query, CarryProductInfo.class);
    }

    /**
     * 根据店铺ID查询被带货的商品ID列表
     *
     * @param shopId 店铺ID
     * @param pageNo 页码
     * @return 结果
     */
    public List<CarryProductInfo> findBeCarriedSpusByShopId(Integer shopId, Integer pageNo) {
        List<AggregationOperation> operations = new ArrayList<>();
        // 查询
        operations.add(match(where("originShopId").is(shopId).and("status").in(CarryProductStatusEnum.NORMAL.getValue(),
                CarryProductStatusEnum.VERIFY_PASS.getValue())));
        // 分组 为了去重
        GroupOperation groupOperation = group("spuId")
                .first("spuId").as("spuId");
        operations.add(groupOperation);
        // 分页
        long pageSize = 10;
        operations.add(skip((pageNo - 1) * pageSize));
        operations.add(limit(pageSize));
        Aggregation agg = newAggregation(operations);
        AggregationResults<CarryProductInfo> results = mongoTemplate.aggregate(agg, CarryProductInfo.class,
                CarryProductInfo.class);
        return results.getMappedResults();
    }

    /**
     * 查询特定店铺下已带货商品信息
     *
     * @param shopId     带货店铺ID
     * @param destShopId 原始店铺ID
     * @param pageNo     分页信息
     * @return 结果
     */
    public List<CarryProductInfo> findCarriedSpusByShopId2(Integer shopId, Integer destShopId, Integer pageNo) {
        Query query = new Query(where("originShopId").is(destShopId).and("shopId").is(shopId).and("status")
                .in(CarryProductStatusEnum.NORMAL.getValue(), CarryProductStatusEnum.VERIFY_PASS.getValue()));
        long pageSize = 10;
        query.skip((pageNo - 1) * pageSize).limit((int) pageSize);
        query.with(Sort.by(Sort.Order.desc("createTime")));
        query.fields().include("spuId");
        return mongoTemplate.find(query, CarryProductInfo.class);
    }

    /**
     * 根据带货商品ID查询原始商品spuId
     *
     * @param carrySpuId 带完货后商品spuId
     * @return 结果
     */
    public CarryProductInfo findOriSpuIdByCarrySpuId(Integer carrySpuId) {
        Query query = new Query(where("carrySpuId").is(carrySpuId));
        return mongoTemplate.findOne(query, CarryProductInfo.class);
    }

    /**
     * 检查带货记录是否存在
     *
     * @param carrySpuId 带货后的商品ID
     * @return 结果
     */
    public boolean existCarryInfo(Integer carrySpuId) {
        Query query = new Query(where("carrySpuId").is(carrySpuId));
        return mongoTemplate.exists(query, CarryProductInfo.class);
    }

    /**
     * 插入新的记录
     *
     * @param carryProductInfo 新的记录
     */
    public void insert(CarryProductInfo carryProductInfo) {
        carryProductInfo.setCreateTime(new Date());
        carryProductInfo.setUpdateTime(new Date());
        mongoTemplate.insert(carryProductInfo);
    }

    /**
     * 根据ID删除记录
     *
     * @param spuIds 原商品ID
     */
    public void deleteByCarrySpuId(List<Integer> spuIds) {
        Query query = new Query(where("carrySpuId").in(spuIds));
        mongoTemplate.remove(query, CarryProductInfo.class);
    }

    public void deleteBySpuIds(List<Integer> spuIds) {
        Query query = new Query(where("spuId").in(spuIds));
        mongoTemplate.remove(query, CarryProductInfo.class);
    }

    /**
     * 根据ID查询所有带货记录
     *
     * @param spuIds 原商品ID
     * @return 结果
     */
    public List<CarryProductInfo> findCarryInfosBySpuIds(List<Integer> spuIds) {
        Query query = new Query(where("spuId").in(spuIds).and("status")
                .in(CarryProductStatusEnum.NORMAL.getValue(), CarryProductStatusEnum.VERIFY_PASS.getValue()));
        return mongoTemplate.find(query, CarryProductInfo.class);
    }

    public long countBeCarriedBySpuId(Integer spuId) {
        Query query = new Query(where("spuId").is(spuId).and("status")
                .in(CarryProductStatusEnum.NORMAL.getValue(), CarryProductStatusEnum.VERIFY_PASS.getValue()));
        return mongoTemplate.count(query, CarryProductInfo.class);
    }
}
